﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using nwrole.Module.lib;
using nwrole.toolbox.sync.ServiceHost;
using nwrole.toolbox.sync.client;

namespace nwrole.toolbox.sync.SourceModule
{
    public class SyncSourceModule : IModule
    {
        [ModuleConfig(60)]
        public int SyncIntervalSeconds { get; set; }

        [ModuleConfig]
        public string SrcDbConnectionString { get; set; }

        [ModuleConfig]
        public string SyncDbConnectionString { get; set; }

        [ModuleConfig]
        public int SyncInstanceId { get; set; }

        [ModuleConfig]
        public int SyncLockSeconds { get; set; }

        // Source Service Connection Info

        [ModuleConfig(Name="SyncSrcServiceConnType")]
        public string SyncSrcServiceConnType { get; set; }

        [ModuleConfig(Name = "SyncSourceService/ServiceBus/ServiceNamespace")]
        public string SyncSrcServiceSBServiceNamespace { get; set; }

        [ModuleConfig(Name = "SyncSourceService/ServiceBus/ServicePath")]
        public string SyncSrcServiceSBServicePath { get; set; }

        [ModuleConfig(Name = "SyncSourceService/ServiceBus/IssuerName")]
        public string SyncSrcServiceSBIssuerName { get; set; }

        [ModuleConfig(Name = "SyncSourceService/ServiceBus/IssuerSecret")]
        public string SyncSrcServiceSBIssuerSecret { get; set; }

        [ModuleConfig(Name = "SyncSourceService/WebService/BaseAddress")]
        public string SyncSrcServiceWSBaseAddress { get; set; }

        [ModuleConfig(Name = "SyncSourceService/WebService/Address")]
        public string SyncSrcServiceWSAddress { get; set; }

        // Destination Service Connection Info

        [ModuleConfig(Name = "SyncDestinationService/ConnType")]
        public string SyncDestServiceConnType { get; set; }

        [ModuleConfig(Name = "SyncDestinationService/ServiceBus/ServiceNamespace")]
        public string SyncDestServiceSBServiceNamespace { get; set; }

        [ModuleConfig(Name = "SyncDestinationService/ServiceBus/ServicePath")]
        public string SyncDestServiceSBServicePath { get; set; }

        [ModuleConfig(Name = "SyncDestinationService/ServiceBus/IssuerName")]
        public string SyncDestServiceSBIssuerName { get; set; }

        [ModuleConfig(Name = "SyncDestinationService/ServiceBus/IssuerSecret")]
        public string SyncDestServiceSBIssuerSecret { get; set; }

        [ModuleConfig(Name = "SyncDestinationService/WebService/BaseAddress")]
        public string SyncDestServiceWSBaseAddress { get; set; }

        [ModuleConfig(Name = "SyncDestinationService/WebService/Address")]
        public string SyncDestServiceWSAddress { get; set; }

        protected IModuleDebug _debug;

        private bool _running = false;

        private AutoResetEvent _waitEvent = new AutoResetEvent(false);

        /*public void Setup(IModuleDebug debug, IModuleSettings settings)
        {
            _debug = debug;
            _settings = settings;

            LoadConfig();
            SaveConfig();
        }*/

        public void Start(IModuleDebug debug)
        {
            _debug = debug;

            debug.RegisterLogger(new ModuleFileLogger(LogLevel.Critical));
            debug.RegisterLogger(new ModuleConsoleLogger(LogLevel.Info));
            debug.RegisterLogger(new ModuleEventLogger(LogLevel.Info));

            Trace.TraceInformation("SyncSourceModule starting");

            //LoadConfig();

            SyncSourceServiceHost srcHost = new SyncSourceServiceHost();
            srcHost.Start(SyncSourceConnInfo, SrcDbConnectionString, SyncDbConnectionString, SyncDestinationConnInfo, new TimeSpan(0, 0, SyncLockSeconds));
            SyncSourceServiceClient client = new SyncSourceServiceClient(SyncSourceConnInfo);

            Trace.TraceInformation("SyncSourceModule running");

            int curSyncIntervalSeconds = SyncIntervalSeconds;
            int retriesLevel = 0;
            int numRetries = 0;

            _running = true;
            while (_running)
            {
                debug.Pulse("Syncing");
                //WriteLog("SyncSourcePlugin syncing " + DateTime.Now);
                //client.SyncAllSyncEntities();
                try
                {
                    if (client.StartFullSync(SyncInstanceId))
                    {
                        while (client.SyncNextEntity(SyncInstanceId))
                        {
                        }
                    }
                    retriesLevel = 0;
                    numRetries = 0;
                    curSyncIntervalSeconds = SyncIntervalSeconds;
                }
                catch (Exception e)
                {
                    Trace.TraceError("SyncSourceModule Error running full sync: " + e);
                    numRetries++;
                    if (numRetries % 10 == 0 && retriesLevel < 3)
                    {
                        retriesLevel++;
                        switch (retriesLevel)
                        {
                            case 1:
                                curSyncIntervalSeconds = SyncIntervalSeconds * 5;
                                break;
                            case 2:
                                curSyncIntervalSeconds = SyncIntervalSeconds * 10;
                                break;
                        }

                        Trace.TraceInformation("SyncSourceModule number of retries reached {0} retries level now {1} curSyncIntervalSec={2}", numRetries, retriesLevel, curSyncIntervalSeconds);

                        if (retriesLevel == 3)
                            throw;

                        numRetries = 0;
                    }
                }

                _waitEvent.WaitOne(curSyncIntervalSeconds * 1000);
            }

            Trace.TraceInformation("SyncSourceModule stopped");
        }

        public void Stop()
        {
            Trace.TraceInformation("SyncSourceModule stopping");
            _running = false;
            _waitEvent.Set();
        }

        /*private void SaveConfig()
        {
            _settings.PutSetting("SyncIntervalSeconds", _syncIntervalSeconds);
            _settings.PutSetting("SrcDbConnectionString", _srcDbConnectionString);
            _settings.PutSetting("SyncDbConnectionString", _syncDbConnectionString);
            _settings.PutSetting("SyncInstanceId", _syncInstanceId);
            _settings.PutSetting("SyncLockSeconds", _syncLockSeconds);

            // Source Service Connection Info

            _settings.PutSetting("SyncSrcService/ConnType", _syncSrcServiceConnType);
            _settings.PutSetting("SyncSrcService/SBServiceNamespace", _syncSrcServiceSBServiceNamespace);
            _settings.PutSetting("SyncSrcService/SBServicePath", _syncSrcServiceSBServicePath);
            _settings.PutSetting("SyncSrcService/SBIssuerName", _syncSrcServiceSBIssuerName);
            _settings.PutSetting("SyncSrcService/SBIssuerSecret", _syncSrcServiceSBIssuerSecret);
            _settings.PutSetting("SyncSrcService/WSBaseAddress", _syncSrcServiceWSBaseAddress);
            _settings.PutSetting("SyncSrcService/WSAddress", _syncSrcServiceWSAddress);

            // Destination Service Connection Info

            _settings.PutSetting("SyncDestService/ConnType", _syncDestServiceConnType);
            _settings.PutSetting("SyncDestService/SBServiceNamespace", _syncDestServiceSBServiceNamespace);
            _settings.PutSetting("SyncDestService/SBServicePath", _syncDestServiceSBServicePath);
            _settings.PutSetting("SyncDestService/SBIssuerName", _syncDestServiceSBIssuerName);
            _settings.PutSetting("SyncDestService/SBIssuerSecret", _syncDestServiceSBIssuerSecret);
            _settings.PutSetting("SyncDestService/WSBaseAddress", _syncDestServiceWSBaseAddress);
            _settings.PutSetting("SyncDestService/WSAddress", _syncDestServiceWSAddress);
        }

        private void LoadConfig()
        {
            _syncIntervalSeconds = _settings.GetSetting("SyncIntervalSeconds", 60);
            _srcDbConnectionString = _settings.GetSetting("SrcDbConnectionString", "");
            _syncDbConnectionString = _settings.GetSetting("SyncDbConnectionString", "");
            _syncInstanceId = _settings.GetSetting("SyncInstanceId", 0);
            _syncLockSeconds = _settings.GetSetting("SyncLockSeconds", 0);

            // Source Service Connection Info

            _syncSrcServiceConnType = _settings.GetSetting("SyncSrcService/ConnType", "");
            _syncSrcServiceSBServiceNamespace = _settings.GetSetting("SyncSrcService/SBServiceNamespace", "");
            _syncSrcServiceSBServicePath = _settings.GetSetting("SyncSrcService/SBServicePath", "");
            _syncSrcServiceSBIssuerName = _settings.GetSetting("SyncSrcService/SBIssuerName", "");
            _syncSrcServiceSBIssuerSecret = _settings.GetSetting("SyncSrcService/SBIssuerSecret", "");
            _syncSrcServiceWSBaseAddress = _settings.GetSetting("SyncSrcService/WSBaseAddress", "");
            _syncSrcServiceWSAddress = _settings.GetSetting("SyncSrcService/WSAddress", "");

            // Destination Service Connection Info

            _syncDestServiceConnType = _settings.GetSetting("SyncDestService/ConnType", "");
            _syncDestServiceSBServiceNamespace = _settings.GetSetting("SyncDestService/SBServiceNamespace", "");
            _syncDestServiceSBServicePath = _settings.GetSetting("SyncDestService/SBServicePath", "");
            _syncDestServiceSBIssuerName = _settings.GetSetting("SyncDestService/SBIssuerName", "");
            _syncDestServiceSBIssuerSecret = _settings.GetSetting("SyncDestService/SBIssuerSecret", "");
            _syncDestServiceWSBaseAddress = _settings.GetSetting("SyncDestService/WSBaseAddress", "");
            _syncDestServiceWSAddress = _settings.GetSetting("SyncDestService/WSAddress", "");
        }*/

        private ServiceConnectionInfo SyncSourceConnInfo
        {
            get
            {
                ServiceConnectionInfo connInfo = new ServiceConnectionInfo();

                ServiceConnectionInfo.ServiceConnectionType type;
                ServiceConnectionInfo.ServiceConnectionType.TryParse(SyncSrcServiceConnType, true, out type);
                connInfo.Type = type;

                connInfo.ServiceBusServiceNamespace = SyncSrcServiceSBServiceNamespace;
                connInfo.ServiceBusServicePath = SyncSrcServiceSBServicePath;
                connInfo.ServiceBusIssuerName = SyncSrcServiceSBIssuerName;
                connInfo.ServiceBusIssuerSecret = SyncSrcServiceSBIssuerSecret;

                connInfo.WebServiceBaseAddress = SyncSrcServiceWSBaseAddress;
                connInfo.WebServiceAddress = SyncSrcServiceWSAddress;

                return connInfo;
            }
        }

        public ServiceConnectionInfo SyncDestinationConnInfo
        {
            get
            {
                ServiceConnectionInfo connInfo = new ServiceConnectionInfo();

                ServiceConnectionInfo.ServiceConnectionType type;
                ServiceConnectionInfo.ServiceConnectionType.TryParse(SyncDestServiceConnType, true, out type);
                connInfo.Type = type;

                connInfo.ServiceBusServiceNamespace = SyncDestServiceSBServiceNamespace;
                connInfo.ServiceBusServicePath = SyncDestServiceSBServicePath;
                connInfo.ServiceBusIssuerName = SyncDestServiceSBIssuerName;
                connInfo.ServiceBusIssuerSecret = SyncDestServiceSBIssuerSecret;

                connInfo.WebServiceBaseAddress = SyncDestServiceWSBaseAddress;
                connInfo.WebServiceAddress = SyncDestServiceWSAddress;

                return connInfo;
            }
        }
    }
}
